#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <assert.h>

#define NUM 1024
#define OPT_NUM 64

char lineCommand[NUM];
char* myargv[OPT_NUM]; 
int lastCode = 0;
int lastSig = 0;

int main()
{
    while(1)
    {
        //输出提示符
        printf("[用户名@主机名 当前路径]# ");
        fflush(stdout);

        //获取用户输入
        char* s = fgets(lineCommand, sizeof(lineCommand) - 1, stdin);
        assert(s != NULL);
        (void)s;
        //清除最后一个\n
        lineCommand[strlen(lineCommand) - 1] = 0;
        //printf("test: %s\n", lineCommand);
        
        //字符串切割
        myargv[0] = strtok(lineCommand, " ");
        int i = 1;
        if(myargv[0] != NULL && strcmp(myargv[0], "ls") == 0)
        {
            myargv[i++] = (char*)"--color=auto";
        }

        while(myargv[i++] = strtok(NULL, " "));
        
        //如果是cd命令，不需要创建子进程，让shell自己执行对应的命令，本质就是执行系统接口
        // 内建命令:不需要让子进程执行，而是shell自己执行的命令
        if(myargv[0] != NULL && strcmp(myargv[0], "cd") == 0)
        {
            if(myargv[1] != NULL) 
            {
                chdir(myargv[1]);
            }
            continue;
        }
        
        if(myargv[0] != NULL && myargv[1] != NULL && strcmp(myargv[0], "echo") == 0)
        {
            if(strcmp(myargv[1], "$?") == 0)
            {
                printf("%d, %d\n", lastCode, lastSig);
            }
            else 
            {
                printf("%s\n", myargv[1]);
            }
            continue; 
        }

        //测试是否成功
#ifdef DEBUG 
        for(i = 0; myargv[i]; ++i)
        {
            printf("myargv[%d]: %s\n", i, myargv[i]);
        }
#endif
        
        // 执行命令
       pid_t id =fork();
       assert(id != -1);

       if(id == 0)
       {
           //child
           execvp(myargv[0], myargv);   //v 参数数组 p 环境变量 e 自己的环境变量 l 采用列表
           exit(1);
       }
       int status = 0;
       pid_t ret = waitpid(id, &status, 0);
       assert(ret > 0);
       (void)ret;    
       lastCode = (status>>8) & 0xFF;
       lastSig = status & 0x7F;
    }

    return 0;
}
